﻿// <copyright file="ExportObjectsToXml.cs" company="Codeplex project Eco.Contrib"> 
// The MIT License (MIT) 
// </copyright> 
// <author>Peter Buchmann</author> 

namespace Eco.Contrib
{
    using System.Collections.Generic;
    using System.Xml;
    using System.Xml.XPath;
    using Eco.Cache;
    using Eco.DataRepresentation;
    using Eco.Framework;
    using Eco.Framework.DefaultImpl;
    using Eco.ObjectRepresentation;
    using Eco.Persistence;
    using Eco.Services;

    /// <summary>
    /// ExportObjectsToXml: Exports objects to XML
    /// </summary>
    public class ExportObjectsToXml : ImportExportBase
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="ExportObjectsToXml"/> class.
        /// </summary>
        /// <param name="keyAttributes">The key attributes.</param>
        public ExportObjectsToXml(KeyAttributeDictionary keyAttributes)
            : base(keyAttributes)
        {
        }

        /// <summary>
        /// Exports the specified object list.
        /// </summary>
        /// <param name="list">The list.</param>
        /// <returns>XML-document of exported objects</returns>
        public IXPathNavigable Export(IObjectList list)
        {
            if (list == null)
            {
                throw new EcoContribException("Parameter list is null");
            }

            ICache cache = list.ServiceProvider.GetEcoService<ICache>();
            IObjectRepresentationProvider orp = list.ServiceProvider.GetEcoService<IObjectRepresentationProvider>();
            List<Locator> locators = new List<Locator>();

            list.EnsureObjects();
            foreach (IObject obj in list)
            {
                locators.Add(orp.LocatorForIObject(obj.ObjectInstance));
            }

            Datablock datablock = PersistenceHandlerImpl.BuildBlockForUpdate(cache, locators, true, true);

            IdConverter idConverter = new IdConverter(cache, orp, this.KeyAttributes);
            DatablockConverter converter = new DatablockConverter(list.ServiceProvider.GetEcoService<ITypeSystemService>().TypeSystem);
            converter.IdToNodeEvent += new DatablockConverter.IdToNodeHandler(idConverter.ConvertIdToNode);
            return converter.ConvertToXml(datablock, true);
        }

        /// <summary>
        /// IdConverter: Id converter
        /// </summary>
        private class IdConverter
        {
            /// <summary>
            /// cache field
            /// </summary>
            private readonly ICache cache;

            /// <summary>
            /// orp field
            /// </summary>
            private readonly IObjectRepresentationProvider orp;

            /// <summary>
            /// Initializes a new instance of the <see cref="IdConverter"/> class.
            /// </summary>
            /// <param name="cache">The cache.</param>
            /// <param name="orp">The orp.</param>
            /// <param name="keyAttributes">The key attributes.</param>
            public IdConverter(ICache cache, IObjectRepresentationProvider orp, KeyAttributeDictionary keyAttributes)
            {
                this.cache = cache;
                this.orp = orp;
                this.KeyAttributes = keyAttributes;
            }

            /// <summary>
            /// Gets or sets the key attributes.
            /// </summary>
            /// <value>
            /// The key attributes.
            /// </value>
            public KeyAttributeDictionary KeyAttributes { get; set; }

            /// <summary>
            /// Converts the id to node.
            /// </summary>
            /// <param name="id">The id.</param>
            /// <param name="node">The node.</param>
            public void ConvertIdToNode(ObjectId id, XmlElement node)
            {
                Locator loc = this.cache.GetEnsuredLocatorById(id);
                IObject obj = this.orp.IObjectForLocator(loc);
                string keyAttribute = this.KeyAttributes.KeyAttributeForType(obj.AsObject.GetType());
                object key = obj.Properties[keyAttribute].AsObject;

                XmlAttribute attr = node.OwnerDocument.CreateAttribute("Type");
                attr.Value = key.GetType().Name;
                node.Attributes.Append(attr);
                node.InnerText = key.ToString();
            }
        }
    }
}
